#include "Repository.h"
#include "DALEntityTranslator.h"
#include "Serialization.h"
#include "Utils.h"
#include "DAL\DALUtils.h"

#define ID_Region 1
#define ID_Product 2
#define ID_Contact 3
#define ID_Customer 4
#define ID_Supplier 5
#define ID_Delivery 6
#define ID_DeliveryBatch 7
#define ID_Supply 8
#define ID_SupplyBatch 9

RepositoryIDControl DefaultIDControl()
{
	RepositoryIDControl result;
	result.AvailableID = 1;
	result.MaximalID = 1;

	return result;
}

//Serialization of ID control entities:

DataEntity RepositoryIDControlToDalEntity(RepositoryIDControl BLLEntity)
{
	DataEntity newDE;

	AllocateDalEntityMemory(&newDE, sizeof(unsigned int)*2);

	SerializeInt(newDE.Data, 0, BLLEntity.AvailableID);
	SerializeInt(newDE.Data, sizeof(unsigned int), BLLEntity.MaximalID);

	return newDE;
}

RepositoryIDControl DalEntityToRepositoryIDControl(DataEntity DALEntity)
{
	RepositoryIDControl newRepositoryIDControl;

	newRepositoryIDControl.AvailableID = DeserializeInt(DALEntity.Data, 0);
	newRepositoryIDControl.MaximalID = DeserializeInt(DALEntity.Data, sizeof(unsigned int));

	return newRepositoryIDControl;
}

void GuarranteeIDControl()
{
	for (int i = ID_Region; i <= ID_SupplyBatch; i++)
	{
		DALResult DR;
		DR = GetEntity("RepositoryIDControl", i);

		//ID control doesn't exist - create a default one
		if (DR.Message == NO_SUCH_ENTITY)
		{
			DataEntity DE = RepositoryIDControlToDalEntity(DefaultIDControl());

			CreateOrEditEntity("RepositoryIDControl", i, DE);

			DestructDataEntity(&DE);
		}

		DestructDALResult(&DR);
	}
}

//ID Control (local functions):
RepositoryIDControl GetRepositoryIDControl(unsigned int EntityID)
{
	DALResult DR = GetEntity("RepositoryIDControl", EntityID);

	return DalEntityToRepositoryIDControl(DR.Result);;
}

void SetRepositoryIDControl(unsigned int EntityID, RepositoryIDControl RIDC)
{
	DataEntity DE = RepositoryIDControlToDalEntity(RIDC);
	CreateOrEditEntity("RepositoryIDControl", EntityID, DE);
}

void NotifyDelete(unsigned int EntityID, unsigned int ID)
{
	RepositoryIDControl currentControl;

	//Illegal EntityID, do nothing
	if (EntityID < ID_Region || EntityID > ID_SupplyBatch)
		return;

	currentControl = GetRepositoryIDControl(EntityID);

	//Deal with available ID
	if (currentControl.AvailableID > ID)
		currentControl.AvailableID = ID;

	//Deal with maximal ID (if we deleted the maximal ID, decrement it, unless it is 1)
	if (currentControl.MaximalID == ID && currentControl.MaximalID > 1)
		currentControl.MaximalID--;

	SetRepositoryIDControl(EntityID, currentControl);
}

unsigned int SeekAvailableID(unsigned int MinimalID, unsigned int EntityID)
{
	//Illegal EntityID, do nothing
	if (EntityID < ID_Region || EntityID > ID_SupplyBatch)
		return 0;

	unsigned int result = MinimalID;

	char* entities[] =
	{
		"RepositoryIDControl",
		"Region",
		"Product",
		"Contact",
		"Customer",
		"Supplier",
		"Delivery",
		"DeliveryBatch",
		"Supply",
		"SupplyBatch"
	};

	DALResult DR;

	while (1)
	{
		DR = GetEntity(entities[EntityID], result);

		if (DR.Message == NO_SUCH_ENTITY)
		{
			break;
		}

		result++;
	}

	DestructDALResult(&DR);

	return result;
}

void NotifyCreate(unsigned int EntityID, unsigned int ID)
{
	RepositoryIDControl currentControl;

	//Illegal EntityID, do nothing
	if (EntityID < ID_Region || EntityID > ID_SupplyBatch)
		return;

	currentControl = GetRepositoryIDControl(EntityID);

	//If we've used up our available ID, we need to seek a new one
	if (currentControl.AvailableID == ID)
		currentControl.AvailableID = SeekAvailableID(ID, EntityID);

	//If the ID that was created is greater than the maximal ID, change the maximal ID to fit it
	if (currentControl.MaximalID < ID)
		currentControl.MaximalID = ID;

	SetRepositoryIDControl(EntityID, currentControl);
}


void EstablishRepository(String RootDirectoryPath)
{
	char* entities[] =
	{	
		"RepositoryIDControl",
		"Region",
		"Product",
		"Contact",
		"Customer",
		"Supplier",
		"Delivery",
		"DeliveryBatch",
		"Supply",
		"SupplyBatch"
	};

	EntityTable RepositoryTable = CreateEntityTable(entities, 10);
	EstablishDataEnvironment(RootDirectoryPath, RepositoryTable);

	GuarranteeIDControl();
}

void FinalizeRepository()
{
	DestructDataEnvironment();
}

void SetRegion(Region Region)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!Region.ID)
		return;

	DE = RegionToDalEntity(Region);

	CreateOrEditEntity("Region", Region.ID, DE);
	NotifyCreate(ID_Region, Region.ID);

	DestructDataEntity(&DE);
}

Region GetRegion(unsigned int ID)
{
	DALResult DR = GetEntity("Region", ID);
	Region result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToRegion(DR.Result);

	return result;
}

void DeleteRegion(unsigned int ID)
{
	NotifyDelete(ID_Region, ID);
	DeleteEntity("Region", ID);
}

RepositoryIDControl RegionIDControl()
{
	RepositoryIDControl result;
	
	DALResult DR = GetEntity("RepositoryIDControl", ID_Region);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

void SetProduct(Product Product)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!Product.ID)
		return;

	DE = ProductToDalEntity(Product);

	CreateOrEditEntity("Product", Product.ID, DE);
	NotifyCreate(ID_Product, Product.ID);

	DestructDataEntity(&DE);
}

Product GetProduct(unsigned int ID)
{
	DALResult DR = GetEntity("Product", ID);
	Product result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToProduct(DR.Result);

	return result;
}

void DeleteProduct(unsigned int ID)
{
	NotifyDelete(ID_Product, ID);
	DeleteEntity("Product", ID);
}

RepositoryIDControl ProductIDControl()
{
	RepositoryIDControl result;

	DALResult DR = GetEntity("RepositoryIDControl", ID_Product);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

void SetContact(Contact Contact)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!Contact.ID)
		return;

	DE = ContactToDalEntity(Contact);

	CreateOrEditEntity("Contact", Contact.ID, DE);
	NotifyCreate(ID_Contact, Contact.ID);

	DestructDataEntity(&DE);
}

Contact GetContact(unsigned int ID)
{
	DALResult DR = GetEntity("Contact", ID);
	Contact result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToContact(DR.Result);

	return result;
}

void DeleteContact(unsigned int ID)
{
	NotifyDelete(ID_Contact, ID);
	DeleteEntity("Contact", ID);
}

RepositoryIDControl ContactIDControl()
{
	RepositoryIDControl result;

	DALResult DR = GetEntity("RepositoryIDControl", ID_Contact);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

void SetCustomer(Customer Customer)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!Customer.ID)
		return;

	DE = CustomerToDalEntity(Customer);

	CreateOrEditEntity("Customer", Customer.ID, DE);
	NotifyCreate(ID_Customer, Customer.ID);

	DestructDataEntity(&DE);
}

Customer GetCustomer(unsigned int ID)
{
	DALResult DR = GetEntity("Customer", ID);
	Customer result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToCustomer(DR.Result);

	return result;
}

void DeleteCustomer(unsigned int ID)
{
	NotifyDelete(ID_Customer, ID);
	DeleteEntity("Customer", ID);
}

RepositoryIDControl CustomerIDControl()
{
	RepositoryIDControl result;

	DALResult DR = GetEntity("RepositoryIDControl", ID_Customer);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

void SetSupplier(Supplier Supplier)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!Supplier.ID)
		return;

	DE = SupplierToDalEntity(Supplier);

	CreateOrEditEntity("Supplier", Supplier.ID, DE);
	NotifyCreate(ID_Supplier, Supplier.ID);

	DestructDataEntity(&DE);
}

Supplier GetSupplier(unsigned int ID)
{
	DALResult DR = GetEntity("Supplier", ID);
	Supplier result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToSupplier(DR.Result);

	return result;
}

void DeleteSupplier(unsigned int ID)
{
	NotifyDelete(ID_Supplier, ID);
	DeleteEntity("Supplier", ID);
}

RepositoryIDControl SupplierIDControl()
{
	RepositoryIDControl result;

	DALResult DR = GetEntity("RepositoryIDControl", ID_Supplier);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

void SetDelivery(Delivery Delivery)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!Delivery.ID)
		return;

	DE = DeliveryToDalEntity(Delivery);

	CreateOrEditEntity("Delivery", Delivery.ID, DE);
	NotifyCreate(ID_Delivery, Delivery.ID);

	DestructDataEntity(&DE);
}

Delivery GetDelivery(unsigned int ID)
{
	DALResult DR = GetEntity("Delivery", ID);
	Delivery result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToDelivery(DR.Result);

	return result;
}

void DeleteDelivery(unsigned int ID)
{
	NotifyDelete(ID_Delivery, ID);
	DeleteEntity("Delivery", ID);
}

RepositoryIDControl DeliveryIDControl()
{
	RepositoryIDControl result;

	DALResult DR = GetEntity("RepositoryIDControl", ID_Delivery);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

void SetDeliveryBatch(DeliveryBatch DeliveryBatch)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!DeliveryBatch.ID)
		return;

	DE = DeliveryBatchToDalEntity(DeliveryBatch);

	CreateOrEditEntity("DeliveryBatch", DeliveryBatch.ID, DE);
	NotifyCreate(ID_DeliveryBatch, DeliveryBatch.ID);

	DestructDataEntity(&DE);
}

DeliveryBatch GetDeliveryBatch(unsigned int ID)
{
	DALResult DR = GetEntity("DeliveryBatch", ID);
	DeliveryBatch result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToDeliveryBatch(DR.Result);

	return result;
}

void DeleteDeliveryBatch(unsigned int ID)
{
	NotifyDelete(ID_DeliveryBatch, ID);
	DeleteEntity("DeliveryBatch", ID);
}

RepositoryIDControl DeliveryBatchIDControl()
{
	RepositoryIDControl result;

	DALResult DR = GetEntity("RepositoryIDControl", ID_DeliveryBatch);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

void SetSupply(Supply Supply)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!Supply.ID)
		return;

	DE = SupplyToDalEntity(Supply);

	CreateOrEditEntity("Supply", Supply.ID, DE);
	NotifyCreate(ID_Supply, Supply.ID);

	DestructDataEntity(&DE);
}

Supply GetSupply(unsigned int ID)
{
	DALResult DR = GetEntity("Supply", ID);
	Supply result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToSupply(DR.Result);

	return result;
}

void DeleteSupply(unsigned int ID)
{
	NotifyDelete(ID_Supply, ID);
	DeleteEntity("Supply", ID);
}

RepositoryIDControl SupplyIDControl()
{
	RepositoryIDControl result;

	DALResult DR = GetEntity("RepositoryIDControl", ID_Supply);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

void SetSupplyBatch(SupplyBatch SupplyBatch)
{
	DataEntity DE;

	//We're not dealing with an ID that is 0
	if (!SupplyBatch.ID)
		return;

	DE = SupplyBatchToDalEntity(SupplyBatch);

	CreateOrEditEntity("SupplyBatch", SupplyBatch.ID, DE);
	NotifyCreate(ID_SupplyBatch, SupplyBatch.ID);

	DestructDataEntity(&DE);
}

SupplyBatch GetSupplyBatch(unsigned int ID)
{
	DALResult DR = GetEntity("SupplyBatch", ID);
	SupplyBatch result;
	result.ID = 0;

	if (DR.Message == SUCCESS)
		result = DalEntityToSupplyBatch(DR.Result);

	return result;
}

void DeleteSupplyBatch(unsigned int ID)
{
	NotifyDelete(ID_SupplyBatch, ID);
	DeleteEntity("SupplyBatch", ID);
}

RepositoryIDControl SupplyBatchIDControl()
{
	RepositoryIDControl result;

	DALResult DR = GetEntity("RepositoryIDControl", ID_SupplyBatch);

	return DalEntityToRepositoryIDControl(DR.Result);

	return result;
}

unsigned int GetAvailableIDForRegion()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Region);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForRegion()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Region);

	return currentControl.MaximalID;
}

unsigned int GetAvailableIDForProduct()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Product);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForProduct()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Product);

	return currentControl.MaximalID;
}

unsigned int GetAvailableIDForContact()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Contact);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForContact()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Contact);

	return currentControl.MaximalID;
}

unsigned int GetAvailableIDForCustomer()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Customer);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForCustomer()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Customer);

	return currentControl.MaximalID;
}

unsigned int GetAvailableIDForSupplier()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Supplier);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForSupplier()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Supplier);

	return currentControl.MaximalID;
}

unsigned int GetAvailableIDForDelivery()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Delivery);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForDelivery()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Delivery);

	return currentControl.MaximalID;
}

unsigned int GetAvailableIDForDeliveryBatch()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_DeliveryBatch);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForDeliveryBatch()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_DeliveryBatch);

	return currentControl.MaximalID;
}

unsigned int GetAvailableIDForSupply()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Supply);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForSupply()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_Supply);

	return currentControl.MaximalID;
}

unsigned int GetAvailableIDForSupplyBatch()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_SupplyBatch);

	return currentControl.AvailableID;
}

unsigned int GetMaximalIDForSupplyBatch()
{
	RepositoryIDControl currentControl = GetRepositoryIDControl(ID_SupplyBatch);

	return currentControl.MaximalID;
}